package com.reactim.message.controller;

import com.reactim.common.response.Result;
import com.reactim.message.dto.MessageResponse;
import com.reactim.message.dto.SendMessageRequest;
import com.reactim.message.entity.Message;
import com.reactim.message.service.MessageService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 消息控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/messages")
@RequiredArgsConstructor
public class MessageController {
    
    private final MessageService messageService;
    
    /**
     * 发送消息
     */
    @PostMapping("/send")
    public Mono<Result<MessageResponse>> sendMessage(@Valid @RequestBody SendMessageRequest request) {
        return messageService.sendMessage(request)
                .map(message -> Result.success("消息发送成功", message))
                .onErrorResume(e -> {
                    log.error("消息发送失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取消息详情
     */
    @GetMapping("/{messageId}")
    public Mono<Result<MessageResponse>> getMessageById(@PathVariable String messageId) {
        return messageService.getMessageById(messageId)
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取消息失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取会话消息列表
     */
    @GetMapping("/conversation/{conversationId}")
    public Mono<Result<List<MessageResponse>>> getConversationMessages(
            @PathVariable String conversationId,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        Pageable pageable = PageRequest.of(page, size);
        return messageService.getConversationMessages(conversationId, pageable)
                .collectList()
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取会话消息失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取私聊消息列表
     */
    @GetMapping("/private")
    public Mono<Result<List<MessageResponse>>> getPrivateMessages(
            @RequestParam Long userId1,
            @RequestParam Long userId2,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        Pageable pageable = PageRequest.of(page, size);
        return messageService.getPrivateMessages(userId1, userId2, pageable)
                .collectList()
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取私聊消息失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取群聊消息列表
     */
    @GetMapping("/group/{groupId}")
    public Mono<Result<List<MessageResponse>>> getGroupMessages(
            @PathVariable Long groupId,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        Pageable pageable = PageRequest.of(page, size);
        return messageService.getGroupMessages(groupId, pageable)
                .collectList()
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取群聊消息失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 撤回消息
     */
    @PutMapping("/{messageId}/recall")
    public Mono<Result<MessageResponse>> recallMessage(
            @PathVariable String messageId,
            @RequestParam Long userId) {
        
        return messageService.recallMessage(messageId, userId)
                .map(message -> Result.success("消息撤回成功", message))
                .onErrorResume(e -> {
                    log.error("消息撤回失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 删除消息
     */
    @DeleteMapping("/{messageId}")
    public Mono<Result<Void>> deleteMessage(
            @PathVariable String messageId,
            @RequestParam Long userId) {
        
        return messageService.deleteMessage(messageId, userId)
                .then(Mono.just(Result.<Void>success("消息删除成功", null)))
                .onErrorResume(e -> {
                    log.error("消息删除失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 编辑消息
     */
    @PutMapping("/{messageId}/edit")
    public Mono<Result<MessageResponse>> editMessage(
            @PathVariable String messageId,
            @RequestParam Long userId,
            @RequestBody Message.MessageContent newContent) {
        
        return messageService.editMessage(messageId, userId, newContent)
                .map(message -> Result.success("消息编辑成功", message))
                .onErrorResume(e -> {
                    log.error("消息编辑失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 标记消息已读
     */
    @PutMapping("/{messageId}/read")
    public Mono<Result<Void>> markMessageAsRead(
            @PathVariable String messageId,
            @RequestParam Long userId) {
        
        return messageService.markMessageAsRead(messageId, userId)
                .then(Mono.just(Result.<Void>success("消息已标记为已读", null)))
                .onErrorResume(e -> {
                    log.error("标记消息已读失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 批量标记消息已读
     */
    @PutMapping("/read/batch")
    public Mono<Result<Void>> markMessagesAsRead(
            @RequestBody List<String> messageIds,
            @RequestParam Long userId) {
        
        return messageService.markMessagesAsRead(messageIds, userId)
                .then(Mono.just(Result.<Void>success("消息已批量标记为已读", null)))
                .onErrorResume(e -> {
                    log.error("批量标记消息已读失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取未读消息数量
     */
    @GetMapping("/unread/count")
    public Mono<Result<Long>> getUnreadMessageCount(@RequestParam Long userId) {
        return messageService.getUnreadMessageCount(userId)
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取未读消息数量失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 搜索消息
     */
    @GetMapping("/search")
    public Mono<Result<List<MessageResponse>>> searchMessages(
            @RequestParam String keyword,
            @RequestParam Long userId,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        Pageable pageable = PageRequest.of(page, size);
        return messageService.searchMessages(keyword, userId, pageable)
                .collectList()
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("搜索消息失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 转发消息
     */
    @PostMapping("/{messageId}/forward")
    public Mono<Result<MessageResponse>> forwardMessage(
            @PathVariable String messageId,
            @RequestParam Long fromUserId,
            @RequestParam(required = false) Long toUserId,
            @RequestParam(required = false) Long groupId) {
        
        return messageService.forwardMessage(messageId, fromUserId, toUserId, groupId)
                .map(message -> Result.success("消息转发成功", message))
                .onErrorResume(e -> {
                    log.error("消息转发失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取消息已读用户列表
     */
    @GetMapping("/{messageId}/read-users")
    public Mono<Result<List<Long>>> getMessageReadUsers(@PathVariable String messageId) {
        return messageService.getMessageReadUsers(messageId)
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取消息已读用户失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取指定时间后的消息
     */
    @GetMapping("/conversation/{conversationId}/after")
    public Mono<Result<List<MessageResponse>>> getMessagesAfter(
            @PathVariable String conversationId,
            @RequestParam String afterTime) {
        
        LocalDateTime dateTime = LocalDateTime.parse(afterTime);
        return messageService.getMessagesAfter(conversationId, dateTime)
                .collectList()
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取指定时间后的消息失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
    
    /**
     * 获取指定序号后的消息
     */
    @GetMapping("/conversation/{conversationId}/sequence/{sequence}")
    public Mono<Result<List<MessageResponse>>> getMessagesAfterSequence(
            @PathVariable String conversationId,
            @PathVariable Long sequence) {
        
        return messageService.getMessagesAfterSequence(conversationId, sequence)
                .collectList()
                .map(Result::success)
                .onErrorResume(e -> {
                    log.error("获取指定序号后的消息失败", e);
                    return Mono.just(Result.error(e.getMessage()));
                });
    }
}